package com.xinlianshiye.im.service.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xinlianshiye.im.ContentBody;
import com.xinlianshiye.im.ResponseBody;
import com.xinlianshiye.im.dao.RecordDao;
import com.xinlianshiye.im.bean.Friend;
import com.xinlianshiye.im.bean.Record;
import com.xinlianshiye.im.service.RecordService;
import com.xinlianshiye.im.response.Page;
import com.xinlianshiye.im.response.RecordPageView;
import com.xinlianshiye.im.response.RecordView;
import com.xinlianshiye.im.utils.RedisReceiver;
import com.xinlianshiye.im.utils.urlgoods.UrlGoods;
import com.xinlianshiye.im.utils.urlgoods.UrlGoodsUtils;
import com.xinlianshiye.clouds.common.exception.WebMessageExceptionBuilder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Transactional
@Service
public class RecordServiceImpl implements RecordService {

    public RecordServiceImpl(RecordDao recordDao, ObjectMapper objectMapper, UrlGoodsUtils urlGoodsUtils, WebMessageExceptionBuilder exceptionBuilder) {
        this.recordDao = recordDao;
        this.objectMapper = objectMapper;
        this.urlGoodsUtils = urlGoodsUtils;
        this.exceptionBuilder = exceptionBuilder;
    }

    private final RecordDao recordDao;
    private final ObjectMapper objectMapper;
    private final UrlGoodsUtils urlGoodsUtils;
    private final WebMessageExceptionBuilder exceptionBuilder;

    @Autowired
    private RedisReceiver redisReceiver;

    @Override
    public Record getOrElseThrow(Integer id) {
        return recordDao.findById(id).orElseThrow(() -> exceptionBuilder.build(1, "记录不存在"));
    }

    // 新增在聊天记录表中发送数据
    private Record send(Integer userId, Integer other, Integer type, String content) {
        // 把之前对方的信息设置为已读
        recordDao.readRecord(userId, other);
        // 发送者存储消息 给发送者拥有
        Record record = new Record();
        record.setOwnerId(userId);
        record.setOtherId(other);
        record.setHaveRead(false);
        record.setSender(true);
        record.setCreateTime(Instant.now());
        record.setDeleted(false);
        record.setType(type);
        record.setContent(content);
        record = recordDao.save(record);
        //发送消息
        redisReceiver.send(record);

        // 接受者存储消息 给接收者拥有
        Record toRecord = new Record();
        toRecord.setOwnerId(other);
        toRecord.setOtherId(userId);
        toRecord.setHaveRead(false);
        toRecord.setSender(false);
        toRecord.setCreateTime(Instant.now());
        toRecord.setType(type);
        toRecord.setContent(content);
        toRecord.setDeleted(false);
        recordDao.save(toRecord);

        //发送消息
        redisReceiver.send(toRecord);
        return record;
    }

    @Override
    public Record send(Integer userId, Integer otherId, ContentBody contentBody) {
        Integer type = contentBody.getType();
        String content = contentBody.getContent();
        try {
            if (contentBody.getType() != null && contentBody.getType().equals(ContentBody.TYPE_TEXT)) {
                UrlGoods goods = urlGoodsUtils.resolve(contentBody.getContent());
                if (goods != null) {
                    content = objectMapper.writeValueAsString(goods);
                    type = ContentBody.TYPE_CUSTOM;
                }
            }
        } catch (JsonProcessingException e) {
            log.error("UrlGoods 序列化出错", e);
        }
        return send(userId, otherId, type, content);
    }

    @Override
    public void read(Integer userId, Integer other) {
        // 把对方发给我的消息变为已读, 并通知对方
        if (recordDao.readRecord(userId, other) > 0) {
            ResponseBody responseBody = ResponseBody.initSuccess("readMessage", null);
            responseBody.setReceiver(other);
            responseBody.setSender(userId);
            redisReceiver.sendToUser(other, responseBody);
        }
    }

    @Override
    public List<Record> listUnRead(Integer ownerId, Integer otherId) {
        // 获取我收到的未读消息
        List<Record> list = recordDao.findAllUnRead(ownerId, otherId);
        // 将消息变为已读
        read(ownerId, otherId);
        return list;
    }

    @Override
    public Page<Record> page4APP(Integer userId, Integer other, Integer start, Integer limit) {
        Page<Record> page = null;
        if (start == null) {
            // 如果start为空， 则查询未读记录
            List<Record> list = recordDao.findAllUnRead(userId, other);
            if (list.size() > 0) {
                page = new Page<>(list, 0, limit, recordDao.count(userId, other), true);
            }
        }
        //如果start不为空， 且没有未读消息， 则返回正常的查询结果
        if (page == null) {
            page = recordDao.page(userId, other, null, null, start, limit);
        }
        // 将消息变为已读
        read(userId, other);
        return page;
    }

    @Override
    public void deleteByFriend(Friend friend) {
        recordDao.deleteByOwnerIdAndOtherId(friend.getUser().getId(), friend.getFriend().getId());
    }

    @Override
    public void delete(Integer ownerId, Integer otherId) {
        List<Record> list = recordDao.findByOwnerIdAndOtherId(ownerId, otherId);
        list.forEach(record -> {
            record.setDeleted(true);
            recordDao.save(record);
        });
    }

    @Override
    public RecordPageView page4PC(Integer ownerId, Integer otherId, Integer start, Integer limit, String keyword, LocalDate startDate) {
        List<LocalDate> durationDate = recordDao.findDurationDate(ownerId, otherId);
        if (startDate == null && durationDate.size() > 1) {
            // 如果开始时间为空 则从聊天记录的最后一天开始查询
            startDate = durationDate.get(1);
        }
        Page<Record> recordPage = recordDao.page(ownerId, otherId, keyword, startDate, start, limit);

        RecordPageView recordPageView = new RecordPageView();
        if (durationDate.size() > 1) {
            recordPageView.setFirstdate(Date.from(durationDate.get(0).atStartOfDay().atZone(ZoneId.systemDefault()).toInstant()));
            recordPageView.setEnddate(Date.from(durationDate.get(1).atStartOfDay().atZone(ZoneId.systemDefault()).toInstant()));
        }
        recordPageView.setPage(
                new Page<>(
                        recordPage.getItems().stream().map(RecordView::init).collect(Collectors.toList()),
                        recordPage.getStart(),
                        recordPage.getLimit(),
                        recordPage.getTotalCount()
                )
        );
        return recordPageView;
    }
}
